home *** CD-ROM | disk | FTP | other *** search
/ The Very Best of Atari Inside / The Very Best of Atari Inside 1.iso / mint / mint110s / debug.c < prev    next >
C/C++ Source or Header  |  1993-09-27  |  14KB  |  639 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992,1993 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. /* MiNT debugging output routines */
  8. /* also, ksprintf is put here, for lack of any better place to put it */
  9.  
  10. #include "mint.h"
  11. #include <stdarg.h>
  12.  
  13. static void VDEBUGOUT P_((int, const char *, va_list));
  14.  
  15. /*
  16.  * ksprintf implements a very crude sprintf() function that provides only
  17.  * what MiNT needs...
  18.  *
  19.  * NOTE: this sprintf probably doesn't conform to any standard at
  20.  * all. It's only use in life is that it won't overflow fixed
  21.  * size buffers (i.e. it won't try to write more than SPRINTF_MAX
  22.  * characters into a string)
  23.  */
  24.  
  25. static int
  26. PUTC(char *p, int c, int *cnt, int width) {
  27.     int put = 1;
  28.  
  29.     if (*cnt <= 0) return 0;
  30.     *p++ = c;
  31.     *cnt -= 1;
  32.     while (*cnt > 0 && --width > 0) {
  33.         *p++ = ' ';
  34.         *cnt -= 1;
  35.         put++;
  36.     }
  37.     return put;
  38. }
  39.  
  40. static int
  41. PUTS(char *p, const char *s, int *cnt, int width) {
  42.     int put = 0;
  43.  
  44.     if (s == 0) s = "(null)";
  45.  
  46.     while (*cnt > 0 && *s) {
  47.         *p++ = *s++;
  48.         put++;
  49.         *cnt -= 1;
  50.         width--;
  51.     }
  52.     while (width-- > 0 && *cnt > 0) {
  53.         *p++ = ' ';
  54.         put++;
  55.         *cnt -= 1;
  56.     }
  57.     return put;
  58. }
  59.  
  60. static int
  61. PUTL(char *p, unsigned long u, int base, int *cnt, int width, int fill_char)
  62. {
  63.     int put = 0;
  64.     static char obuf[32];
  65.     char *t;
  66.  
  67.     t = obuf;
  68.  
  69.     do {
  70.         *t++ = "0123456789ABCDEF"[u % base];
  71.         u /= base;
  72.         width--;
  73.     } while (u > 0);
  74.  
  75.     while (width-- > 0 && *cnt > 0) {
  76.         *p++ = fill_char;
  77.         put++;
  78.         *cnt -= 1;
  79.     }
  80.     while (*cnt > 0 && t != obuf) {
  81.         *p++ = *--t;
  82.         put++;
  83.         *cnt -= 1;
  84.     }
  85.     return put;
  86. }
  87.  
  88. int
  89. vksprintf(char *buf, const char *fmt, va_list args)
  90. {
  91.     char *p = buf, c, fill_char;
  92.     char *s_arg;
  93.     int i_arg;
  94.     long l_arg;
  95.     int cnt;
  96.     int width, long_flag;
  97.  
  98.     cnt = SPRINTF_MAX - 1;
  99.     while( (c = *fmt++) != 0 ) {
  100.         if (c != '%') {
  101.             p += PUTC(p, c, &cnt, 1);
  102.             continue;
  103.         }
  104.         c = *fmt++;
  105.         width = 0;
  106.         long_flag = 0;
  107.         fill_char = ' ';
  108.         if (c == '0') fill_char = '0';
  109.         while (c && isdigit(c)) {
  110.             width = 10*width + (c-'0');
  111.             c = *fmt++;
  112.         }
  113.         if (c == 'l' || c == 'L') {
  114.             long_flag = 1;
  115.             c = *fmt++;
  116.         }
  117.         if (!c) break;
  118.  
  119.         switch (c) {
  120.         case '%':
  121.             p += PUTC(p, c, &cnt, width);
  122.             break;
  123.         case 'c':
  124.             i_arg = va_arg(args, int);
  125.             p += PUTC(p, i_arg, &cnt, width);
  126.             break;
  127.         case 's':
  128.             s_arg = va_arg(args, char *);
  129.             p += PUTS(p, s_arg, &cnt, width);
  130.             break;
  131.         case 'd':
  132.             if (long_flag) {
  133.                 l_arg = va_arg(args, long);
  134.             } else {
  135.                 l_arg = va_arg(args, int);
  136.             }
  137.             if (l_arg < 0) {
  138.                 p += PUTC(p, '-', &cnt, 1);
  139.                 width--;
  140.                 l_arg = -l_arg;
  141.             }
  142.             p += PUTL(p, l_arg, 10, &cnt, width, fill_char);
  143.             break;
  144.         case 'o':
  145.             if (long_flag) {
  146.                 l_arg = va_arg(args, long);
  147.             } else {
  148.                 l_arg = va_arg(args, unsigned int);
  149.             }
  150.             p += PUTL(p, l_arg, 8, &cnt, width, fill_char);
  151.             break;
  152.         case 'x':
  153.             if (long_flag) {
  154.                 l_arg = va_arg(args, long);
  155.             } else {
  156.                 l_arg = va_arg(args, unsigned int);
  157.             }
  158.             p += PUTL(p, l_arg, 16, &cnt, width, fill_char);
  159.             break;
  160.         case 'u':
  161.             if (long_flag) {
  162.                 l_arg = va_arg(args, long);
  163.             } else {
  164.                 l_arg = va_arg(args, unsigned int);
  165.             }
  166.             p += PUTL(p, l_arg, 10, &cnt, width, fill_char);
  167.             break;
  168.  
  169.         }
  170.     }
  171.     *p = 0;
  172.     return (int)(p - buf);
  173. }
  174.  
  175. int ARGS_ON_STACK 
  176. ksprintf(char *buf, const char *fmt, ...)
  177. {
  178.     va_list args;
  179.     int foo;
  180.  
  181.     va_start(args, fmt);
  182.     foo = vksprintf(buf, fmt, args);    
  183.     va_end(args);
  184.     return foo;
  185. }
  186.  
  187. int debug_level = 1;    /* how much debugging info should we print? */
  188. int out_device = 2;    /* BIOS device to write errors to */
  189.  
  190. /*
  191.  * out_next[i] is the out_device value to use when the current
  192.  * device is i and the user hits F3.
  193.  * Cycle is CON -> PRN -> AUX -> MIDI -> 6 -> 7 -> 8 -> 9 -> CON
  194.  * (Note: BIOS devices 6-8 exist on Mega STe and TT, 9 on TT.)
  195.  *
  196.  * out_device and this table are exported to bios.c and used here in HALT().
  197.  */
  198.  
  199. /*            0  1  2  3  4  5  6  7  8  9 */
  200. char out_next[] = { 1, 3, 0, 6, 0, 0, 7, 8, 9, 2 };
  201.  
  202. /*
  203.  * debug log modes:
  204.  *
  205.  * 0: no logging.
  206.  * 1: log all messages, dump the log any time something happens at
  207.  *    a level that gets shown.  Thus, if you're at debug_level 2,
  208.  *    everything is logged, and if something at levels 1 or 2 happens,
  209.  *    the log is dumped.
  210.  *
  211.  * LB_LINE_LEN is 20 greater than SPRINTF_MAX because up to 20 bytes
  212.  * are prepended to the buffer string passed to ksprintf.
  213.  */
  214.  
  215. #define LBSIZE 50                /* number of lines */
  216. #define LB_LINE_LEN (SPRINTF_MAX+20)        /* width of a line */
  217. int debug_logging;
  218. int logptr;
  219. static char logbuf[LBSIZE][LB_LINE_LEN];
  220. static short logtime[LBSIZE];    /* low 16 bits of 200Hz: timestamp of msg */
  221.  
  222. /*
  223.  * Extra terse settings - don't even output ALERTs unless asked to.
  224.  *
  225.  * Things that happen in on an idle Desktop are at LOW_LEVEL:
  226.  * Psemaphore, Pmsg, Syield.
  227.  */
  228.  
  229. #define FORCE_LEVEL 0
  230. #define ALERT_LEVEL 1
  231. #define DEBUG_LEVEL 2
  232. #define TRACE_LEVEL 3
  233. #define LOW_LEVEL 4
  234.  
  235. /*
  236.  * The inner loop does this: at each newline, the keyboard is polled. If
  237.  * you've hit a key, then it's checked: if it's ctl-alt, do_func_key is
  238.  * called to do what it says, and that's that.  If not, then you pause the
  239.  * output.  If you now hit a ctl-alt key, it gets done and you're still
  240.  * paused.  Only hitting a non-ctl-alt key will get you out of the pause. 
  241.  * (And only a non-ctl-alt key got you into it, too!)
  242.  *
  243.  * When out_device isn't the screen, number keys give you the same effects
  244.  * as function keys.  The only way to get into this code, however, is to
  245.  * have something produce debug output in the first place!  This is
  246.  * awkward: Hit a key on out_device, then hit ctl-alt-F5 on the console so
  247.  * bios.c will call DUMPPROC, which will call ALERT, which will call this.
  248.  * It'll see the key you hit on out_device and drop you into this loop.
  249.  * CTL-ALT keys make BIOS call do_func_key even when out_device isn't the
  250.  * console.
  251.  */
  252.  
  253. void
  254. debug_ws(s)
  255.     const char *s;
  256. {
  257.     long key;
  258.     int scan;
  259.     int stopped;
  260.  
  261.     while (*s) {
  262.     (void)Bconout(out_device, *s);
  263.     while (*s == '\n' && out_device != 0 && Bconstat(out_device)) {
  264.         stopped = 0;
  265.         while (1) {
  266.         if (out_device == 2) {
  267.         /* got a key; if ctl-alt then do it */
  268.             if ((Kbshift(-1) & 0x0c) == 0x0c) {
  269.             key = Bconin(out_device);
  270.             scan = (int) (((key >> 16) & 0xff));
  271.             do_func_key(scan);
  272.             goto ptoggle;
  273.             }
  274.         }
  275.         else {
  276.             key = Bconin(out_device);
  277.             if (key < '0' || key > '9') {
  278. ptoggle:        /* not a func key */
  279.             if (stopped) break;
  280.             else stopped = 1;
  281.             }
  282.             else {
  283.             /* digit key from debug device == Fn */
  284.             if (key == '0') scan = 0x44;
  285.             else scan = (int) (key - '0' + 0x3a);
  286.             do_func_key(scan);
  287.             }
  288.         }
  289.         }
  290.     }
  291.     s++;
  292.     }
  293. }
  294.  
  295. /*
  296.  * _ALERT(s) returns 1 for success and 0 for failure.
  297.  * It attempts to write the string to "the alert pipe," u:\pipe\alert.
  298.  * If the write fails because the pipe is full, we "succeed" anyway.
  299.  *
  300.  * This is called in vdebugout and also in memprot.c for memory violations.
  301.  * It's also used by the Salert() system call in dos.c.
  302.  */
  303.  
  304. int
  305. _ALERT(s)
  306. char *s;
  307. {
  308.     FILEPTR *f;
  309.     char alertbuf[SPRINTF_MAX+10], *ptr, *lastspace;
  310.     int counter;
  311.     char *alert;
  312.     int olddebug = debug_level;
  313.     int oldlogging = debug_logging;
  314.  
  315. /* temporarily reduce the debug level, so errors finding
  316.  * u:\pipe\alert don't get reported
  317.  */
  318.     debug_level = debug_logging = 0;
  319.     f = do_open("u:\\pipe\\alert",(O_WRONLY | O_NDELAY),0,(XATTR *)0);
  320.     debug_level = olddebug;
  321.     debug_logging = oldlogging;
  322.  
  323.     if (f) {
  324. /*
  325.  * format the string into an alert box
  326.  */
  327.     if (*s == '[') {    /* already an alert */
  328.         alert = s;
  329.     } else {
  330.         alert = alertbuf;
  331.         ksprintf(alertbuf, "[1][%s", s);
  332. /*
  333.  * make sure no lines exceed 30 characters; also, filter out any
  334.  * reserved characters like '[' or ']'
  335.  */
  336.         ptr = alertbuf+4;
  337.         counter = 0;
  338.         lastspace = 0;
  339.         while(*ptr) {
  340.             if (*ptr == ' ') {
  341.                 lastspace = ptr;
  342.             } else if (*ptr == '[') {
  343.                 *ptr = '(';
  344.             } else if (*ptr == ']') {
  345.                 *ptr = ')';
  346.             } else if (*ptr == '|') {
  347.                 *ptr = ':';
  348.             }
  349.             if (counter++ >= 29) {
  350.                 if (lastspace) {
  351.                     *lastspace = '|';
  352.                     counter = (int) (ptr - lastspace);
  353.                     lastspace = 0;
  354.                 } else {
  355.                     *ptr = '|';
  356.                     counter = 0;
  357.                 }
  358.             }
  359.             ptr++;
  360.         }
  361.         strcpy(ptr, "][  OK  ]");
  362.     }
  363.  
  364.     (*f->dev->write)(f,alert,(long)strlen(alert)+1);
  365.     do_close(f);
  366.     return 1;
  367.     }
  368.     else return 0;
  369. }
  370.  
  371. static void
  372. VDEBUGOUT(level, s, args)
  373.     int level;
  374.     const char *s;
  375.     va_list args;
  376. {
  377.     char *lp;
  378.     char *lptemp;
  379.  
  380.     logtime[logptr] = (short)(*(long *)0x4baL);
  381.     lp = logbuf[logptr];
  382.     if (++logptr == LBSIZE) logptr = 0;
  383.  
  384.     if (curproc) {
  385.         ksprintf(lp,"pid %3d (%s): ", curproc->pid, curproc->name);
  386.         lptemp = lp+strlen(lp);
  387.     }
  388.     else {
  389.         lptemp = lp;
  390.     }
  391.  
  392.     vksprintf(lptemp, s, args);
  393.  
  394.     /* for alerts, try the alert pipe unconditionally */
  395.     if (level == ALERT_LEVEL && _ALERT(lp)) return;
  396.  
  397.     if (debug_level >= level) {
  398.         debug_ws(lp);
  399.         debug_ws("\r\n");
  400.     }
  401. }
  402.  
  403. void ARGS_ON_STACK Tracelow(const char *s, ...)
  404. {
  405.     va_list args;
  406.  
  407.     if (debug_logging || (debug_level >= LOW_LEVEL)) {
  408.         va_start(args, s);
  409.         VDEBUGOUT(LOW_LEVEL, s, args);
  410.         va_end(args);
  411.     }
  412. }
  413.  
  414. void ARGS_ON_STACK Trace(const char *s, ...)
  415. {
  416.     va_list args;
  417.  
  418.     if (debug_logging || (debug_level >= TRACE_LEVEL)) {
  419.         va_start(args, s);
  420.         VDEBUGOUT(TRACE_LEVEL, s, args);
  421.         va_end(args);
  422.     }
  423. }
  424.  
  425. void ARGS_ON_STACK Debug(const char *s, ...)
  426. {
  427.     va_list args;
  428.  
  429.     if (debug_logging || (debug_level >= DEBUG_LEVEL)) {
  430.         va_start(args, s);
  431.         VDEBUGOUT(DEBUG_LEVEL, s, args);
  432.         va_end(args);
  433.     }
  434.     if (debug_logging && debug_level >= DEBUG_LEVEL) DUMPLOG();
  435. }
  436.  
  437. void ARGS_ON_STACK ALERT(const char *s, ...)
  438. {
  439.     va_list args;
  440.  
  441.     if (debug_logging || debug_level >= ALERT_LEVEL) {
  442.         va_start(args, s);
  443.         VDEBUGOUT(ALERT_LEVEL, s, args);
  444.         va_end(args);
  445.     }
  446.     if (debug_logging && debug_level >= ALERT_LEVEL) DUMPLOG();
  447. }
  448.  
  449. void ARGS_ON_STACK FORCE(const char *s, ...)
  450. {
  451.     va_list args;
  452.  
  453.     va_start(args, s);
  454.     VDEBUGOUT(FORCE_LEVEL, s, args);
  455.     va_end(args);
  456.     /* don't dump log here - hardly ever what you mean to do. */
  457. }
  458.  
  459. void
  460. DUMPLOG()
  461. {
  462.     char *end;
  463.     char *start;
  464.     short *timeptr;
  465.     char timebuf[6];
  466.  
  467.     /* logbuf[logptr] is the oldest string here */
  468.  
  469.     end = start = logbuf[logptr];
  470.     timeptr = &logtime[logptr];
  471.  
  472.     do {
  473.         if (*start) {
  474.         ksprintf(timebuf,"%04x ",*timeptr);
  475.         debug_ws(timebuf);
  476.         debug_ws(start);
  477.         debug_ws("\r\n");
  478.         *start = '\0';
  479.         }
  480.         start += LB_LINE_LEN;
  481.         timeptr++;
  482. #ifdef LATTICE
  483. #pragma ignore 83    /* [reference beyond object size] */
  484. #endif
  485.         if (start == logbuf[LBSIZE]) {
  486. #ifdef LATTICE
  487. #pragma warning 83    /* [reference beyond object size] */
  488. #endif
  489.         start = logbuf[0];
  490.         timeptr = &logtime[0];
  491.         }
  492.         } while (start != end);
  493.  
  494.         logptr = 0;
  495. }
  496.  
  497. /* wait for a key to be pressed */
  498. void
  499. PAUSE()
  500. {
  501.     debug_ws("Hit a key\r\n");
  502.     (void)Bconin(2);
  503. }
  504.   
  505. EXITING
  506. void ARGS_ON_STACK FATAL(const char *s, ...)
  507. {
  508.     va_list args;
  509.  
  510.     va_start(args, s);
  511.     VDEBUGOUT(-1, s, args);
  512.     va_end(args);
  513.     if (debug_logging) {
  514.         DUMPLOG();
  515.     }
  516.  
  517.     HALT();
  518. }
  519.  
  520.  
  521. static const char *rebootmsg[MAXLANG] = {
  522. "FATAL ERROR. You must reboot the system.\r\n",
  523. "FATALER FEHLER. Das System muß neu gestartet werden.\r\n",    /* German */
  524. "FATAL ERROR. You must reboot the system.\r\n",        /* French */
  525. "FATAL ERROR. You must reboot the system.\r\n",        /* UK */
  526. "FATAL ERROR. You must reboot the system.\r\n",        /* Spanish */
  527. "FATAL ERROR. You must reboot the system.\r\n"        /* Italian */
  528. };
  529.  
  530. EXITING 
  531. void HALT()
  532. {
  533.     long r;
  534.     long key;
  535.     int scan;
  536.     extern long tosssp;    /* in main.c */
  537. #ifdef PROFILING
  538.     extern EXITING _exit P_((int));
  539. #endif
  540.     restr_intr();    /* restore interrupts to normal */
  541. #ifdef DEBUG_INFO
  542.     debug_ws("Fatal MiNT error: adjust debug level and hit a key...\r\n");
  543. #else
  544.     debug_ws(rebootmsg[gl_lang]);
  545. #endif
  546.     sys_q[READY_Q] = 0;    /* prevent context switches */
  547.  
  548.     for(;;) {
  549.         /* get a key; if ctl-alt then do it, else halt */
  550.         key = Bconin(out_device);
  551.         if ((key & 0x0c000000L) == 0x0c000000L) {
  552.             scan = (int) ((key >> 16) & 0xff);
  553.             do_func_key(scan);
  554.         }
  555.         else {
  556.             break;
  557.         }
  558.     }
  559.     for(;;) {
  560.         debug_ws(rebootmsg[gl_lang]);
  561.         r = Bconin(2);
  562.  
  563.         if ( (r & 0x0ff) == 'x' ) {
  564.             extern int no_mem_prot;
  565.             close_filesys();
  566.             if (!no_mem_prot)
  567.                 restr_mmu();
  568.             restr_screen();
  569.             (void)Super((void *)tosssp);    /* gratuitous (void *) for Lattice */
  570. #ifdef PROFILING
  571.             _exit(0);
  572. #else
  573.             Pterm0();
  574. #endif
  575.         }
  576.     }
  577. }
  578.  
  579.  
  580. /* some key definitions */
  581. #define CTRLALT 0xc
  582. #define DEL 0x53    /* scan code of delete key */
  583. #define UNDO 0x61    /* scan code of undo key */
  584.  
  585. void
  586. do_func_key(scan)
  587.     int scan;
  588. {
  589.     extern struct tty con_tty;
  590.  
  591.     switch (scan) {
  592.     case DEL:
  593.         reboot();
  594.         break;
  595.     case UNDO:
  596.         killgroup(con_tty.pgrp, SIGQUIT);
  597.         break;
  598. #ifdef DEBUG_INFO
  599.     case 0x3b:        /* F1: increase debugging level */
  600.         debug_level++;
  601.         break;
  602.     case 0x3c:        /* F2: reduce debugging level */
  603.         if (debug_level > 0)
  604.             --debug_level;
  605.         break;
  606.     case 0x3d:        /* F3: cycle out_device */
  607.         out_device = out_next[out_device];
  608.         break;
  609.     case 0x3e:        /* F4: set out_device to console */
  610.         out_device = 2;
  611.         break;
  612.     case 0x3f:        /* F5: dump memory */
  613.         DUMP_ALL_MEM();
  614.         break;
  615.     case 0x58:        /* shift+F5: dump kernel allocated memory */
  616.         NALLOC_DUMP();
  617.         break;
  618.     case 0x40:        /* F6: dump processes */
  619.         DUMPPROC();
  620.         break;
  621.     case 0x41:        /* F7: toggle debug_logging */
  622.         debug_logging ^= 1;
  623.         break;
  624.     case 0x42:        /* F8: dump log */
  625.         DUMPLOG();
  626.         break;
  627.     case 0x43:        /* F9: dump the global memory table */
  628.         QUICKDUMP();
  629.         break;
  630.     case 0x5c:        /* shift-F9: dump the mmu tree */
  631.         BIG_MEM_DUMP(1,curproc);
  632.         break;
  633.     case 0x44:        /* F10: do an annotated dump of memory */
  634.         BIG_MEM_DUMP(0,0);
  635.         break;
  636. #endif
  637.     }
  638. }
  639.